/* filter methods */
function Filter(map, tmp, collections, controls) {
    var self = this;
    var isVenue = false;
    var filterType = {
        date: 0,
        location: 1,
        text: 2
    }
    var helper = new Helper();

    this.setVenue = function (value) {
        isVenue = value
    }
    // filter by date
    this.date = function (from, to) {
        if(from == null || to == null)
            return;
        this.reset(filterType.date);
        var result = $.grep(collections.events, function(event,i){
            var date = new Date(event.startDate*1000).setHours(0, 0, 0, 0);
            if(date >= from && date <= to)
                return true;
            else
                return false;
        });
        this.update(result);
    }
    // filter by location
    this.location = function(location, city, country) {
        this.reset(filterType.location);
        var empty = new RegExp(/^\s+$/);

        if(country.match(empty) && city.match(empty))
            this.update(collections.events);
        else {
            if(city.match(empty))
                location = country;
            var result = $.grep(collections.events, function(event,i){
                if(event.venue.location.city == location || event.venue.location.country == location)
                    return true;
                else
                    return false;
            });
            this.update(result);
        }
    }
    // filter by any text
    this.text = function(text) {
        this.reset(filterType.text)
        var regexp = new RegExp(text, 'gi');
        var result = $.grep(collections.events, function(event,i){
            if(event.venue.location.city.match(regexp) ||
                event.venue.location.country.match(regexp) ||
                event.venue.location.street.match(regexp) ||
                event.venue.location.postalcode.match(regexp) ||
                helper.date.getDate(event.startDate).match(regexp) ||
                event.venue.name.match(regexp) ||
                event.title.match(regexp) ||
                event.title.match(regexp) ||
                self.artist(event, regexp))
                return true;
            else
                return false;
        });
        this.update(result);
    }
    // reset filter
    this.reset = function (type){
        if(collections.events.length != 0) {
            if(type != filterType.date){
                $('#from').val("");
                $('#to').val("");
            }
            if(type != filterType.location){
                $("#cities").val($("#cities option:first").val());
                $("#countries").val($("#countries option:first").val());
            }
            if(type != filterType.text){
                $('#filter').val("");
            }

            map.marker.removeAll();
            map.window.removeAll();
            $('#filter-event').html('');
        }
    }
    // update filter result
    this.update = function (result){
        $.each(result, function(i, event){
            if(!isVenue)
                map.window.add(tmp.render.infoWindow(event), map.marker.add(event));
            $('#filter-event').append(tmp.render.event(i, event));
        });
        if(isVenue)
            map.window.add(tmp.render.infoWindow(collections.events[0]), map.marker.add(collections.events[0]));
    }
    // filter each artist
    this.artist = function (event, regexp) {
        var result = false;
        $.each(event.artists, function(i, artist) {
            if(artist.match(regexp)) {
                result = true;
                return false;
            }
        });
        return result;
    }
    // filter cities by country
    this.city = {
        fill: function(country){
            var cities;
            if(country.match(new RegExp(/^\s+$/)))
                cities = collections.cities;
            else {
                cities = $.map(collections.events, function(event){
                    if(event.venue.location.country == country)
                        return event.venue.location.city;
                });
                $.uniqueArray(cities);
            }
            controls.city.html('').append( $('<option></option>').html('&nbsp;'));
            $.each(cities.sort(), function(i, city) {
                controls.city.append( $('<option></option>').html(city) )
            });
        }
    }
}

/* location methods */
function Location() {
    var self = this;
    var url = 'http://en.wikipedia.org/w/api.php?callback=?';
    var searchParam = {
        format: "json",
        action: "query",
        list: "search",
        srlimit: 1,
        srwhat: "text"
    }
    var parseParam = {
        format: "json",
        action: "parse"
    }

    this.search = function(city){
        self.google.imageSearch(city);
        self.wikipedia.search(city);
    }

    this.google = {
        imageSearch: function(city) {
            var imageSearch = new google.search.ImageSearch();
            imageSearch.setSearchCompleteCallback(self, self.google.callback, [imageSearch]);
            imageSearch.setRestriction(
                google.search.ImageSearch.RESTRICT_IMAGETYPE,
                google.search.ImageSearch.IMAGETYPE_PHOTO
                );
            imageSearch.setResultSetSize(8);
            imageSearch.execute(city);
        },
        callback: function(searcher){
            if (searcher.results && searcher.results.length > 0) {
                var found = false;
                for (var i = 0; i < searcher.results.length; i++) {
                    var result = searcher.results[i];
                    if(result.width > result.height){
                        $('.collapsePanelContent img').attr('src',result.url);
                        $('.collapsePanelContent').removeClass('hidden');
                        found  = true;
                        break;
                    }
                }
                if(!found) {
                    $('.collapsePanelContent img').attr('src',searcher.results[0].url);
                    $('.collapsePanelContent').removeClass('hidden');
                }
            }
        }
    }
    this.wikipedia = {
        search: function(city) {
            parseParam.page = city;
            $.getJSON(url, parseParam, function(data) {
                var content = jQuery(("<div>" + data.parse.text["*"])
                    .replace(/<img src="\/[^>]+>/g, "")
                    );
                content.find("table").remove();
                var summary = content.find("p:first").text().replace(/\[.+?\]/g, "");
                var helper = new Helper();
                $('.collapsePanelContent p').html(helper.string.truncate(summary, 100, '...'));
                $('.loading:first').remove();
            });
        }
    }
}

/* event methods*/
function Event(map, tmp, collections, controls, dates) {
    var self = this;
    var params = {
        limit: 5,
        page: 1
    }

    this.datepicker = {
        calc: function(event) {
            var date = new Date(event.startDate*1000)
            if(dates.minDate == null || dates.minDate > date)
                dates.toMinDate = dates.minDate = date;
            if(dates.maxDate == null || dates.maxDate < date)
                dates.maxDate = date;
        },
        fill: function() {
            controls.datepicker.datepicker({
                minDate: dates.minDate,
                maxDate: dates.maxDate
            });
        }
    }

    this.location = {
        getIp2Location: function () {
            var url = '/location/geo/ip2loc'
            $.getJSON(url, function(data) {
                if(data.returncode == 200){
                    var url = '/location/events/lat/' + data.position.latitude + '/lng/' + data.position.longitude + '/within/10';
                    var location = new Location();
                    location.search(city);
                    $('#main-content h1:first').html('Events near ' + data.city + ', ' + data.region + ', ' + data.country);
                    map.setCenter(new google.maps.LatLng(data.position.latitude, data.position.longitude));
                    self.location.getEvents(url);
                }
            });
        },
        getGeoLocation: function () {
            if(navigator.geolocation) {
                navigator.geolocation.getCurrentPosition(function(position) {
                    var url = '/location/events/lat/' + position.coords.latitude + '/lng/' + position.coords.longitude + '/within/10';
                    var geocoder = new google.maps.Geocoder();
                    var latLng = new google.maps.LatLng(position.coords.latitude, position.coords.longitude);
                    map.setCenter(latLng);
                    geocoder.geocode( {
                        'latLng': latLng
                    }, function(results, status) {
                        if (status == google.maps.GeocoderStatus.OK) {
                            var city, region, country;
                            $.each(results[0].address_components, function(i, address) {
                                if(address.types[0] == 'locality')
                                    city = address.long_name;
                                if(address.types[0] == 'administrative_area_level_1')
                                    region = address.long_name;
                                if(address.types[0] == 'country')
                                    country = address.long_name;
                            });
                            var location = new Location();
                            location.search(city);
                            $('#main-content h1:first').html('Events near ' + city + ', ' + region + ', ' + country);
                        }
                    });
                    self.location.getEvents(url);
                }, function() {
                    self.location.getIp2Location();
                });
            }else{
                self.location.getIp2Location();
            }
        },
        getEvents: function (url) {
            self.artist.getEvents(url);
        },
        fill: function() {
            $.each(collections.events, function(i, event){
                if(event.venue.location.country != "")
                    collections.countries.push(event.venue.location.country);
                if(event.venue.location.city != "")
                    collections.cities.push(event.venue.location.city);
            });
            // fill city select
            $.uniqueArray(collections.cities);
            $.each(collections.cities.sort(), function(i, city) {
                controls.city.append( $('<option></option>').html(city) )
            });
            // fill country select
            $.uniqueArray(collections.countries);
            $.each(collections.countries.sort(), function(i, country) {
                controls.country.append($('<option></option>').html(country) )
            });
        }
    }

    this.artist = {
        getEvents: function (url) {
            $.getJSON(url, params, function(data) {
                $.each(data.events, function(i, event){
                    if(event.venue.location.point.latitude != 0 && event.venue.location.point.longitude != 0) {
                        collections.events.push(event);
                        map.window.add(tmp.render.infoWindow(event), map.marker.add(event));
                        controls.panel.append(tmp.render.event(collections.events.length - 1, event));
                        self.datepicker.calc(event);
                    }
                });
                params.page++;
                if(data.totalPages == 0)
                    controls.panel.append(tmp.getEventNotFound());
                else if(params.page <= data.totalPages) {
                    if(params.page == 2)
                        map.setCenter(new google.maps.LatLng(collections.events[0].venue.location.point.latitude,
                            collections.events[0].venue.location.point.longitude))
                    self.artist.getEvents(url);
                } else {
                    if(params.page == 2)
                        map.setCenter(new google.maps.LatLng(collections.events[0].venue.location.point.latitude,
                            collections.events[0].venue.location.point.longitude))
                    self.location.fill();
                    self.datepicker.fill();
                }
            });
        }
    }
    this.venue = {
        getEvents: function (url) {
            $.getJSON(url, function(data) {
                if(data.events.length == 0) {
                    url = url.replace(/events/g, 'venue2');
                    $.getJSON(url, function(data) {
                        map.setCenter(new google.maps.LatLng(data.events[0].venue.location.point.latitude,
                            data.events[0].venue.location.point.longitude));
                        map.window.add(tmp.render.infoWindow(data.events[0]), map.marker.add(data.events[0]));
                        map.window.open(0);
                        controls.panel.append(tmp.getEventNotFound());
                    });
                } else {
                    $.each(data.events, function(i, event){
                        collections.events.push(event);
                        controls.panel.append(tmp.render.event(0, event));
                        self.datepicker.calc(event);
                    });
                    map.setCenter(new google.maps.LatLng(data.events[0].venue.location.point.latitude,
                        data.events[0].venue.location.point.longitude));
                    map.window.add(tmp.render.infoWindow(data.events[0]), map.marker.add(data.events[0]));
                    self.datepicker.fill();
                }
            });
        }
    }
}

/* template methods */
function Template() {
    var event_tmp;
    var infoWindow_tmp = '<p class="location">{location}</p>';
    var eventNotFound_tmp = '<li><div class="event"><p class="title">No Events found</p></div></li>';
    var helper = new Helper();

    this.setEventTemplate = function(tmp) {
        event_tmp = tmp;
    }
    this.getEventNotFound = function() {
        return eventNotFound_tmp;
    }

    this.render = {
        event: function(id, event) {
            var tmp = event_tmp.replace(/{id}/g, id);
            tmp = tmp.replace(/{date}/g, helper.date.getDate(event.startDate));
            tmp = tmp.replace(/{day}/g, helper.date.getDay(event.startDate));
            tmp = tmp.replace(/{month}/g, helper.date.getMonth(event.startDate));
            tmp = tmp.replace(/{title}/g, event.title);
            tmp = tmp.replace(/{url}/g, event.url);
            tmp = tmp.replace(/{headliner}/g, event.artists['headliner']);
            tmp = tmp.replace(/{artists}/g, function(){
                var artists = "";
                $.each(event.artists, function(i, artist){
                    if(artist != event.artists['headliner'])
                        artists = artists + artist + " | ";
                });
                return artists;
            });
            tmp = tmp.replace(/{location}/g, function(){
                var location = "";
                if(event.venue.name)
                    location = "<b>" + event.venue.name + "</b><br/>";
                if(event.venue.location.street)
                    location = location + event.venue.location.street + "<br/>";
                if(event.venue.location.postalcode)
                    location = location + event.venue.location.postalcode + " ";
                if(event.venue.location.city)
                    location = location + event.venue.location.city + " | ";
                if(event.venue.location.country)
                    location = location + event.venue.location.country;
                return location;
            });
            return tmp;
        },
        infoWindow: function(event) {
            var tmp = infoWindow_tmp.replace(/{location}/g, function(){
                var location = "";
                if(event.venue.name)
                    location = "<b>" + event.venue.name + "</b><br/>";
                if(event.venue.location.street)
                    location = location + event.venue.location.street + "<br/>";
                if(event.venue.location.postalcode)
                    location = location + event.venue.location.postalcode + " ";
                if(event.venue.location.city)
                    location = location + event.venue.location.city + " | ";
                if(event.venue.location.country)
                    location = location + event.venue.location.country;
                return location;
            });
            return tmp;
        }
    }
}

/* helper methods*/
function Helper()
{
    
    this.string = {
        truncate: function  (text, limit, append) {
            if (typeof text !== 'string')
                return '';
            if (typeof append == 'undefined')
                append = '...';
            var parts = text.split(' ');
            if (parts.length > limit) {
                // loop backward through the string
                for (var i = parts.length - 1; i > -1; --i) {
                    // if i is over limit, drop this word from the array
                    if (i+1 > limit) {
                        parts.length = i;
                    }
                }
                // add the truncate append text
                parts.push(append);
            }
            // join the array back into a string
            return parts.join(' ');
        }
    }

    /* date methods*/
    this.date = {
        // formatted long date from unix timestamp
        getDate: function (timestamp) {
            var date = new Date(timestamp*1000);
            return date.format("ddd dd, mmmm yyyy");
        },
        // day from unix timestamp
        getDay: function (timestamp) {
            var date = new Date(timestamp*1000);
            return date.format("dd");
        },
        // month from unix timestamp
        getMonth: function (timestamp) {
            var date = new Date(timestamp*1000);
            return date.format("mmm").toUpperCase();
        }
    }
}

/* google map facade */
function Map(mapCanvas) {
    var markers = new Array();
    var infoWindows = new Array();
    var polylines = new Array();
    var currentOpenWindow = null;
    var currentZoom = 4;

    var map = new google.maps.Map(mapCanvas, {
        zoom: currentZoom,
        center: new google.maps.LatLng(47.467093,8.127136),
        streetViewControl: false,
        mapTypeId: google.maps.MapTypeId.ROADMAP
    });

    this.setCenter = function(position) {
        map.setCenter(position);
    }

    this.polyline = {
        add: function(event){
            polylines.push(new google.maps.LatLng(event.venue.location.point.latitude,
                event.venue.location.point.longitude));
        },
        show: function() {
            var tour = new google.maps.Polyline({
                path: polylines,
                strokeColor: "#FF0000",
                strokeOpacity: 1.0,
                strokeWeight: 2
            });
            tour.setMap(map);
        }
    }

    /* marker methods. */
    this.marker = {
        removeAll: function () {
            if (markers) {
                for (i in markers) {
                    google.maps.event.clearInstanceListeners(markers[i]);
                    markers[i].setMap(null);
                }
                markers.length = 0;
            }
        },
        add: function(event) {
            var center = new google.maps.LatLng(event.venue.location.point.latitude, event.venue.location.point.longitude);
            var marker = new google.maps.Marker({
                position: center,
                map: map,
                title: event.venue.name + ', ' + event.venue.location.city
            });
            marker.setMap(map);
            markers.push(marker);
            return marker;
        }
    }

    /* window methods. */
    this.window = {
        removeAll: function() {
            if (infoWindows) {
                infoWindows.length = 0;
            }
        },
        add: function(content, marker) {
            var infoWindow = new google.maps.InfoWindow({
                content: content
            });
            infoWindows.push(infoWindow);

            google.maps.event.addListener(infoWindow, 'closeclick', function() {
                map.setZoom(currentZoom);
                currentOpenWindow = null;
            });

            google.maps.event.addListener(marker, 'mouseover', function() {
                if(currentOpenWindow == null)
                    infoWindow.open(map,marker);
            });

            google.maps.event.addListener(marker, 'mouseout', function() {
                if(currentOpenWindow == null)
                    infoWindow.close(map,marker);
            });

            google.maps.event.addListener(marker, 'click', function() {
                var id = markers.indexOf(marker);
                if(currentOpenWindow == id) {
                    map.setZoom(currentZoom);
                    infoWindows[id].close(map, markers[id]);
                    currentOpenWindow = null;
                } else {
                    if(currentOpenWindow != null)
                        infoWindows[currentOpenWindow].close(map, markers[id]);
                    map.setCenter(markers[id].position);
                    map.setZoom(16);
                    infoWindows[id].open(map, markers[id]);
                    currentOpenWindow = id;
                }
            });
        },
        open: function (id) {
            if(id < markers.length && currentOpenWindow == null) {
                map.setCenter(markers[id].position);
                infoWindows[id].open(map, markers[id]);
            }
        },
        close: function (id) {
            if(id < markers.length && currentOpenWindow == null)
                infoWindows[id].close(map, markers[id]);
        },
        toggle: function (id) {
            if(id < markers.length)
            {
                if(currentOpenWindow == id)
                {
                    map.setZoom(currentZoom);
                    infoWindows[id].close(map, markers[id]);
                    currentOpenWindow = null;
                }else
                {
                    if(currentOpenWindow != null)
                        infoWindows[currentOpenWindow].close(map, markers[id]);

                    map.setCenter(markers[id].position);
                    map.setZoom(16);
                    infoWindows[id].open(map, markers[id]);
                    currentOpenWindow = id;
                }
            }
        }
    }
}

/*
jquery-uniqueArray extension
By: William Skidmore - www.wskidmore.com
----------------------------------------------------------*/
jQuery.extend({
    uniqueArray: function(array){
        if ($.isArray(array)){
            var dupes = {};
            var len, i;
            for (i=0,len=array.length;i<len;i++){
                var test = array[i].toString();
                if (dupes[test]) {
                    array.splice(i,1);
                    len--;
                    i--;
                } else {
                    dupes[test] = true;
                }
            }
        } else {
            if (window.console) console.log('Not passing an array to uniqueArray, returning whatever you sent it - not filtered!');
            return(array);
        }
        return(array);
    }
});
